<?php

namespace App\Dao;

use App\Actions\MessageAction;
use App\Actions\PaycallAction;
use App\Dao\Mongodb\UserChatFlagDao;
use App\Model\PayCall;
use App\Model\User;
use App\Utils\FunUtil;
use App\Utils\MemcacheClient;
use App\Utils\MongoDBClient;
use App\Utils\RedisClient;
use Hyperf\Context\ApplicationContext;
use Hyperf\DbConnection\Db;
use Psr\Container\ContainerExceptionInterface;
use Psr\Container\NotFoundExceptionInterface;

class PayCallDao
{
    private static $instance;

    public static function getInstance()
    {
        if (!self::$instance) {
            self::$instance = Applicationcontext::getcontainer()->get(self::class);
        }
        return self::$instance;
    }

    // 获取视频中的用户ID
    public function getCallingUsers()
    {
        $current_time = time();
        // $records = $this->findAll("anchor_id, user_id", "ctime > ? and start_time >? and end_time > ?", [$current_time - 1800, $current_time - 1800, $current_time - 60]);
        $records = PayCall::query()->select(["anchor_id", "user_id"])->where("ctime", ">", $current_time - 1800)->where("start_time", ">", $current_time - 1800)
            ->where("end_time", ">", $current_time - 60)
            ->get()->toArray();
        $calling_uids = [];
        foreach ($records as $record) {
            $calling_uids[] = $record["anchor_id"];
            $calling_uids[] = $record["user_id"];
        }
        return $calling_uids;
    }


    /**
     * 获取某uid最近一次聊天通话记录
     * @param $uid //用户或者主播
     * @param bool $is_anchor 是否是主播
     * @param bool $nocache
     * @return mixed $ret array
     * @throws ContainerExceptionInterface
     * @throws NotFoundExceptionInterface
     */
    public function getLastItemByUid($uid, bool $is_anchor = true, bool $nocache = false)
    {
        $ret = MemcacheClient::getInstance()->get('last_pay_call_item_' . $uid);
        if ($ret === false || $nocache) {
            // if ($is_anchor) {
            //     $where = "anchor_id = ?";
            // } else {
            //     $where = "user_id = ?";
            // }
            // $bindVal = array($uid);
            //
            // $sql = "select * from {$this->table} where $where order by id desc limit 1";
            // $pd = $this->createCommand($sql);
            // $pd->execute($bindVal);
            // $ret = $pd->fetch(PDO::FETCH_ASSOC);
            if ($is_anchor) {
                $ret = PayCall::query()->where("anchor_id", $uid)->orderBy("id", "desc")->first();

            } else {
                $ret = PayCall::query()->where("user_id", $uid)->orderBy("id", "desc")->first();
            }
            $ret = modelToArray($ret);
            MemcacheClient::getInstance()->set('last_pay_call_item_' . $uid, $ret, 60);
        }

        return $ret;
    }


    /**
     * 判断是否处于通话中
     * @param $uid 用户或主播
     * @param bool $is_anchor 是否是主播
     * @param bool $nocache
     * @return bool
     * @throws ContainerExceptionInterface
     * @throws NotFoundExceptionInterface
     */
    public function checkIsCalling($uid, bool $is_anchor = true, bool $nocache = true)
    {
        $result = $this->getLastItemByUid($uid, $is_anchor, $nocache);
        $paycallAction = new PaycallAction();
        if (!empty($result) && $result['status'] == 0) {
            //一分钟未接通，主动挂断
            if ($result['start_time'] == 0 && ($result['ctime'] + 60) < time()) {
                //用户自己还有未完成的通话，立刻结束，防止锁住主播
                // $this->updateByWhere(array("status" => 1, "extend" => '1'), "id = {$result['id']} and status=0");
                PayCall::query()->where('id', $result['id'])->where('status', 0)->update(['status' => 1, 'extend' => '1']);
                MemcacheClient::getInstance()->delete('the_pay_call_' . $result['id']);
                MemcacheClient::getInstance()->delete('last_pay_call_item_' . $uid);
            } else if ($result['end_time'] > 0 && ($result['end_time'] + 60) < time()) {
                //结算
                //先把金币给主播，再结束通话
                $paycallAction->getProfitForCall($result, $is_anchor);
                // $this->updateByWhere(array("status" => 1, "extend" => '42'), "id = {$result['id']} and status = 0");
                PayCall::query()->where('id', $result['id'])->where('status', 0)->update(['status' => 1, 'extend' => '42']);
                MemcacheClient::getInstance()->delete('the_pay_call_' . $result['id']);
                MemcacheClient::getInstance()->delete('last_pay_call_item_' . $uid);
            } else {
                return true; //通话中
            }
        }
        return false; //空闲中
    }


    //用缓存保持自己在线
    public function keepAliveStatus($uid, $call_id)
    {
        RedisClient::getInstance()->setex('keepAliveStatus_' . $call_id . '_' . $uid, 30, time());
        // Mem::set('keepAliveStatus_' . $call_id . '_' . $uid, time(), PAY_CALL_TIME_OUT);
    }

    //看对方是否在线
    public function verifyOtherStatus($uid, $call_id)
    {
        $res = RedisClient::getInstance()->get('keepAliveStatus_' . $call_id . '_' . $uid);
        if ($res) {
            return true;
        } else {
            return false;
        }
    }

    /**
     * 获取用户未读消息
     * @param $uid
     * @return mixed
     * @throws ContainerExceptionInterface
     * @throws NotFoundExceptionInterface
     */
    public function getLastMessagePayCall($uid)
    {
        $userInfo = User::query()->where('id', $uid)->first();
        $userInfo = modelToArray($userInfo);
        $uid = $userInfo['id'];
        $imei = $userInfo['imei'];

        $data = [];
        $mon = MongoDBClient::getInstance();

        //查找上次拉取数据之后的数据
        $lastMsgWhere['uid'] = (int)$uid;
        $lastMsgWhere['unique'] = (string)$imei;
        $lastMsgOption['limit'] = 1;
        $lastMsg = $mon->find('tb_user_chat_flag', $lastMsgWhere, $lastMsgOption);
        //使用毫秒级
        $micotime = microtime(true);
        $defaultFindMsgTime = $micotime - 86400 * 3;
        $findMsgTime = $defaultFindMsgTime;
        if (!empty($lastMsg)) {
            $lastMsgTime = $lastMsg[0]['last_time'];
            if (15289440240 < $lastMsgTime) {
                $lastMsgTime = $lastMsgTime / 1000;
            }
            $findMsgTime = max($lastMsgTime, $defaultFindMsgTime);
        }
        $where['receive_uid'] = (int)$userInfo['id'];
        $where['ctime']['$gt'] = $findMsgTime;
        $where['ctime']['$lte'] = $micotime;

        $where['chat_type']['$in'] = [2]; //用户和主播之间的视频音频通话请求
        $where['chat_type']['$in'][] = 7; //用户和主播之间的视频音频通话请求
        $where['chat_type']['$in'][] = 10; //视频语音通话用户接听群发

        $whereOption['sort'] = array('_id' => -1);
        $whereOption['limit'] = 100;
        $records = $mon->find('tb_user_chat_v2', $where, $whereOption);
        if (!empty($records)) {
            $records = array_reverse($records);
            foreach ($records as $v) {
                unset($v['ip']);
                unset($v['service_id']);
                unset($v['channel_number']);
                unset($v['_id']);
                unset($v['from']);
                unset($v['version_code']);
                unset($v['m_id']);
                unset($v['look']);

                if (in_array($v['content_type'], array(4, 5))) {
                    if (isset($v['call_data'])) {
                        $v['call_data'] = json_decode($v['call_data'], true);
                        // $v['call_price'] = $v['call_data']['call_price'];
                    }
                }

                $data[] = $v;
            }
        }

        if (!empty($data)) {
            //标记最后拉取时间
            UserChatFlagDao::getInstance()->updateLastTimeFlag($uid, $imei, $micotime);

            foreach ($data as $k1 => $v1) {
                $tarUserInfo = User::query()->where('id', $v1['uid'])->first();
                $tarUserInfo = modelToArray($tarUserInfo);
                $format = (new MessageAction())->formatUserInfo($tarUserInfo);
                if (!empty($format) && $format['sex'] == 2) {
                    $call_show_type = $format['call_show_type'];
                    $call_show = $format['call_show'];

                    if ($call_show_type == 1) {
                        $format['video_url'] = $call_show;
                        $format['photo_url'] = '';
                    } elseif ($call_show_type == 2) {
                        $format['video_url'] = '';
                        $format['photo_url'] = $call_show;
                    } else {
                        $format['video_url'] = '';
                        $format['photo_url'] = '';
                    }
                    $format['remarks_name'] = '';
                } else {
                    $format['video_url'] = '';
                    $format['photo_url'] = '';
                }
                $data[$k1]['user_info'] = $format;
                $data[$k1]['is_hello'] = 0;
                $data[$k1]['sort_type'] = 0;

                // 用户亲密度
                if ($tarUserInfo['sex'] == 1) {
                    $data[$k1]['closeness'] = ClosenessDao::read($v1['uid'], $v1['receive_uid']);
                } else {
                    $data[$k1]['closeness'] = ClosenessDao::read($v1['receive_uid'], $v1['uid']);
                }
            }
        }
        $data = array_values($data);
        $res['data'] = $data;
        return $res;
    }

    /**
     * 根据主键查询
     * @param $id
     * @return array
     */
    public function getCallCache($id, $nocache = false)
    {
        $data = MemcacheClient::getInstance()->get('the_pay_call_' . $id);
        if ($data === false || $nocache) {
            $data = PayCall::query()->where('id', $id)->first();
            $data = modelToArray($data);
            MemcacheClient::getInstance()->set('the_pay_call_' . $id, $data, 300);
        }

        return $data;
    }


    /**
     * Note - 更新pay_call记录里的用户的各个金额
     * DateTime 2024/8/2 11:04
     * User Admin
     * @param $fare
     * @param $call_id
     * @param $user_account
     * @param $type
     * @return int
     */
    public function updateCallAmount($fare, $call_id, $user_account, $type = 1)
    {

        $user_coin = $user_account - $fare;
        $data = [
            'fare' => Db::raw('fare + ' . $fare),
            'user_coin' => $user_coin,
            'last_pay_time' => time()
        ];
        if ($type == 2) {
            // $bindVal = array($fare, $user_coin, time(), time() - 1, $call_id);
            $last_pay_time = $data['last_pay_time'] - 1;
        } else {
            // $bindVal = array($fare, $user_coin, time(), time() - 30, $call_id);
            $last_pay_time = $data['last_pay_time'] - 30;
        }
        return PayCall::query()->where('id', $call_id)->where('last_pay_time', '<', $last_pay_time)->update($data);

        // $sql = "update {$this->table} set fare = fare + ?,user_coin = ?,last_pay_time = ? where last_pay_time <= ? and id = ?";
        // $pd = $this->createCommand($sql);
        // $pd->execute($bindVal);
        // return $pd->rowCount();
    }

    // 只更新pay_call记录里关于主播的字段
    public function updateCallAnchorAmount($profit, $call_id, $anchor_account)
    {
        // $sql = "update {$this->table} set profit = profit + ?,anchor_account = ?  where profit = ? and id = ?";
        // $pd = $this->createCommand($sql);
        // $pd->execute(array($profit, $anchor_account, 0, $call_id));
        // return $pd->rowCount();
        return PayCall::query()->where('id', $call_id)->where('profit', '0')->update([
            'profit' => Db::raw('profit + ' . $profit),
            'anchor_account' => $anchor_account
        ]);
    }


    /**
     * Note - 获取今日用户免费匹配通话次数
     * DateTime 2024/8/9 11:01
     * User Admin
     * @param $user_id
     * @return mixed
     */
    public function getFreeVideoCount($user_id)
    {
        $s_time = strtotime(date("Y-m-d ") . "00:00:00");
        $e_time = strtotime(date("Y-m-d ") . "23:59:59");
        // $sql = "select count(id) as count from {$this->table} where ctime between {$s_time} and {$e_time} and user_id = ? and free_video_time>0 and end_time>0";
        // $pd = $this->createCommand($sql);
        // $pd->execute(array($user_id));
        // $res = $pd->fetch(PDO::FETCH_ASSOC);
        // return $res['count'];
        return PayCall::query()->where('user_id', $user_id)->where('free_video_time', '>', 0)->where('end_time', '>', 0)->whereBetween('ctime', [$s_time, $e_time])->count();

    }


    /**
     * Note - 未读消息数量
     * DateTime 2024/8/15 11:52
     * User Admin
     * @param $where
     * @param $bindVal
     * @return false|int|mixed
     */
    public function notReadNum($where)
    {
        // $where = $where != '' ? ' WHERE ' . $where : '';
        // $sql = "SELECT count(*) as num FROM {$table} p {$where} ";
        // $model = $this->conn->prepare($sql);
        // $model->execute($bindVal);
        // $res=$model->fetch(PDO::FETCH_ASSOC);
        // return $res['num']?:0;
        return PayCall::query()->where($where)->count();
    }


    /**
     * Note - 根据match_id获取拒绝的（$field）user_id和anchor_id
     * DateTime 2024/8/19 18:24
     * User Admin
     * @param $match_id
     * @param $field
     * @param $extend
     * @return array
     */
    public function getRefuseByMatchId($match_id, $field, $extend = 31)
    {
        // $sql = "SELECT id,anchor_id,user_id FROM {$this->table} WHERE match_id = ? AND extend = ?";
        // $pd = $this->createCommand($sql);
        // $pd->execute([$match_id, $extend]);
        // $rs = $pd->fetchAll(PDO::FETCH_ASSOC);
        $rs = PayCall::query()->where('match_id', $match_id)->where('extend', $extend)->get()->toArray();
        return array_unique(array_column($rs, $field));
    }


    /**
     * Note - 获取今日匹配过的用户id
     * DateTime 2024/8/19 18:25
     * User Admin
     * @param $uid
     * @param $is_anchor
     * @return array
     */
    public function getTodayMatchUid($uid, $is_anchor = false)
    {
        $time = time() - 24 * 3600;
        $t = time() - 600;
        // 获取10分钟内匹配过的用户 被拒接过的用户
        $field = "id,user_id as uid";
        // $where = "match_id<>0 and ((anchor_id={$uid} and ctime>{$time} and extend=61 ) or (ctime>{$t}))";
        $query = PayCall::query()->where('match_id', '<>', 0)
            ->where(function ($query) use ($uid, $time, $t) {
                $query->where(function ($q) use ($uid, $time, $t) {
                    $q->where('anchor_id', $uid)->where('ctime', '>', $time)->where('extend', 61);
                })
                    ->orWhere(function ($q) use ($t) {
                        $q->orWhere('end_time', '>', $t);
                    });
            });

        if (!$is_anchor) {
            $field = "id,anchor_id as uid,ctime";
            // $where = "match_id<>0 and user_id={$uid} and ctime>{$time} and end_time>0";
            $query->where('user_id', $uid)->where('ctime', '>', $time)->where('end_time', '>', 0);
        }

        // $sql = "SELECT {$field} FROM {$this->table} WHERE {$where}";
        // $pd = $this->createCommand($sql);
        // $pd->execute([]);
        // $rs = $pd->fetchAll(PDO::FETCH_ASSOC);
        // PayCall::query()->where('match_id', '<>',0)
        //     ->where(function ($query) use ($uid, $time){
        //         $query->where('anchor_id', $uid)->where('ctime', '>', $time)->where('extend', 61)->orWhere(function ($query) use ($uid, $time){
        //             $query->where('end_time', '>', 0);
        //         });
        //     })->when($is_anchor, function ($query) use ($uid, $time){
        //         $query->where('user_id', $uid)->where('ctime', '>', $time)->where('extend', 61);
        //     })
        $rs = $query->selectRaw($field)->get()->toArray();
        return array_column($rs, 'uid');
    }


    // 通知主播群发的视频的请求已被人接通
    public function massRefuse($uid, $session_id, $userId, $call_data, $anchorId, $type)
    {
        $send_list = array();
        $insertData = array();
        $insertData['uid'] = (int)$anchorId;
        $insertData['content'] = '通知主播群发的通话的请求已被人接通';
        $insertData['ctime'] = time();
        $insertData['is_hello'] = 0;
        $insertData['content_type'] = $type == 1 ? 4 : 5; // 4：视频通话请求，5：语音通话请求
        $insertData['audio_time'] = 0;
        $insertData['chat_type'] = 40;  //通知主播群发的视频的请求已被人接通
        $insertData['date'] = date("Y-m-d");
        foreach ($call_data as $id) {
            if ($userId != $id) {
                $send_list[] = $id;
            }
        }
        if (!empty($send_list)) {
            //通过socket消息转发，不再通过mongo表记录
            $socket_data = array('uid_list' => $send_list, 'message' => $insertData);
            FunUtil::socket_client('send_message', $uid, $session_id, $socket_data);
        }
    }


}